package fun.codedesign.yinxue.util.event;

import fun.codedesign.yinxue.util.ArrayUtil;
import fun.codedesign.yinxue.util.ReflectUtil;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class EventBus {

    Map<Class<?>, List<MethodInvoker>> handlers = new LinkedHashMap<>();

    public void publish(Object event) {
        handlers.get(event.getClass()).forEach(methodInvoker -> methodInvoker.invoke(event));
    }

    public void register(Object handler) {
        List<Method> methods = ReflectUtil.getMethodsByClass(handler.getClass());
        methods.forEach(method -> {
            if (method.isAnnotationPresent(EventHandler.class)) {
                Class<?>[] classes = method.getParameterTypes();
                if (ArrayUtil.isNotEmpty(classes)) {
                    // 取第一个class
                    Class<?> clazz = classes[0];
                    handlers.computeIfAbsent(clazz, k -> new ArrayList<>());
                    handlers.get(clazz).add(new MethodInvoker(method, handler));
                }
            }
        });
    }

    public static class MethodInvoker {
        Method method;
        Object src;

        public MethodInvoker(Method method, Object src) {
            this.method = method;
            this.src = src;
        }

        public void invoke(Object event) {
            try {
                method.invoke(src, event);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
